package cn.brilliantfuture.commentry.lockers.impl;

import java.sql.Timestamp;
import java.text.MessageFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.UserTransaction;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.log4j.Logger;

import cn.brilliantfuture.commentry.entity.EmailInfo;
import cn.brilliantfuture.commentry.entity.Lockers;
import cn.brilliantfuture.commentry.entity.Purchaser;
import cn.brilliantfuture.commentry.entity.SmsInfo;
import cn.brilliantfuture.commentry.entity.StorageServiceInfo;
import cn.brilliantfuture.commentry.entity.StorageServiceKey;
import cn.brilliantfuture.commentry.entity.UserGroup;
import cn.brilliantfuture.commentry.inform.InformMessageLocal;
import cn.brilliantfuture.commentry.lockers.GoodsClubMessageLocal;
import cn.brilliantfuture.commentry.util.BaseMessageImpl;
import cn.brilliantfuture.commentry.util.CRC8;
import cn.brilliantfuture.commentry.util.CommEntryUtil;
import cn.brilliantfuture.commentry.util.DateTimeHelper;
import cn.brilliantfuture.commentry.util.EMAILScheduler;
import cn.brilliantfuture.commentry.util.HttpUtil;
import cn.brilliantfuture.commentry.util.SMSScheduler;

/**
 * 
 * Title: Communication Entry
 * 
 * Author:  LiTian  
 *
 * Date: 2013-2-4
 * 
 * Description:
 * 
 */
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class GoodsClubMessageImpl extends BaseMessageImpl implements GoodsClubMessageLocal{
	protected static final Logger logger = Logger.getLogger(GoodsClubMessageImpl.class);
	
	@PersistenceContext(unitName = "commentry-jpa")
	private EntityManager entityManager;
	
	@Resource
	SessionContext sessionContext;
	
	@EJB InformMessageLocal informMessage;

	@SuppressWarnings("unchecked")
	public boolean createStorageKey(int userId, String businessCode, int groupId, int lockersId) {
		UserTransaction ut = sessionContext.getUserTransaction();
		
		try {
			ut.begin();
			
			List<Lockers> lockersList = entityManager.createQuery("select l from Lockers l where l.storageBusiness = true and l.lockersId = " + lockersId).getResultList();
			
			if (null == lockersList || lockersList.size() == 0){
				throw new Exception("Lockers is not exist!");
			}
			
			Lockers lockers = lockersList.get(0);
			
			List<StorageServiceKey> storageServiceKeys = entityManager.createQuery("select ssk from StorageServiceKey ssk where ssk.enable = 1 and ssk.lockers.lockersId = " + lockersId + " and ssk.purchaser.purchaserId = " + userId + " and ssk.groupId = " + groupId).getResultList();
			
			StorageServiceKey storageServiceKey = null;
			
			if (null == storageServiceKeys || storageServiceKeys.size() == 0){
				storageServiceKey = new StorageServiceKey();
				
				Purchaser purchaser = new Purchaser();
				purchaser.setPurchaserId(userId);
				storageServiceKey.setPurchaser(purchaser);
				storageServiceKey.setLockers(lockers);
				storageServiceKey.setGroupId(groupId);
				storageServiceKey.setOrderCode(businessCode);
				storageServiceKey.setInsertTime(new Date());
				storageServiceKey.setEnable(true);
				
				entityManager.persist(storageServiceKey);
			} 
			
			StringBuffer sb = new StringBuffer();
			StringBuffer ids = new StringBuffer();
			if (null != storageServiceKey){
				List<StorageServiceKey> list = entityManager.createQuery("select ssk from StorageServiceKey ssk where ssk.enable = 1 and ssk.storageServiceKeyId != " + storageServiceKey.getStorageServiceKeyId() + " and ssk.purchaser.purchaserId = " + userId + " and ssk.groupId = " + groupId).getResultList();
				
				if (null != list && list.size() > 0){
					for (int i = 0; i < list.size(); i++) {
						StorageServiceKey info = list.get(i);
						
						sb.append(info.getLockers().getDevice().getDeviceSn());
						sb.append(",");
						sb.append(info.getStorageServiceKeyId());
						
						ids.append(info.getStorageServiceKeyId());
						if (i < list.size() - 1){
							sb.append("|");
							ids.append(",");
						}
					}
					
					System.out.println(sb.toString());
					
					if (!ids.toString().equals("")){
						entityManager.createQuery("update StorageServiceKey ssk set ssk.enable = 0 where ssk.storageServiceKeyId in (" + ids.toString() + ")").executeUpdate();
					}
				}
			}
			
			entityManager.flush();
			
			ut.commit();
			
			if (!sb.toString().equals("")){
				String result = HttpUtil.getInvoke(getRemoteUrl() + "/storekeys/?type=3&data=" + sb.toString());
				if (!Boolean.parseBoolean(result))
					throw new Exception("Remove store key fail!");
			}

			return true;
		} catch (Exception e) {
			try {
				ut.rollback();
			} catch (Exception e1) {
				logger.error("Rollback fail\n" + e1.getMessage());
			}
			logger.error("Create storage service key fail!\n" + e.getMessage());
		}
		
		return false;
	}

	@SuppressWarnings("unchecked")
	public String createStorageRfid(int userId, String businessCode, int groupId, int lockersId) {
		UserTransaction ut = sessionContext.getUserTransaction();
		
		try {
			ut.begin();

			List<Lockers> lockersList = entityManager.createQuery("select l from Lockers l where l.storageBusiness = true and l.lockersId = " + lockersId).getResultList();
			
			if (null == lockersList || lockersList.size() == 0){
				throw new Exception("Lockers is not exist!");
			}
			
			Lockers lockers = lockersList.get(0);

			List<StorageServiceInfo> storageServiceInfos = entityManager.createQuery("select ssi from StorageServiceInfo ssi where ssi.lockers.lockersId = " + lockersId + " and ssi.number = '" + businessCode + "' and ssi.groupId = " + groupId + " and ssi.enable = 1").getResultList();
			
			StorageServiceInfo storageServiceInfo = null;
			
			if (null == storageServiceInfos || storageServiceInfos.size() == 0){
				storageServiceInfo = new StorageServiceInfo();
				
				Purchaser purchaser = entityManager.find(Purchaser.class, userId);

				autoCreateRfid(storageServiceInfo, lockers.getLockersSn());

				storageServiceInfo.setPurchaser(purchaser);
				storageServiceInfo.setLockers(lockers);
				storageServiceInfo.setGroupId(groupId);
				storageServiceInfo.setNumber(businessCode);
				storageServiceInfo.setEnable(true);
				storageServiceInfo.setInsertTime(new Date());
				
				entityManager.persist(storageServiceInfo);
			} else {
				storageServiceInfo = storageServiceInfos.get(0);
			}

			Map<String, Object> informMap = informMessage.queryInformMessage(storageServiceInfo.getPurchaser().getLanguage(), 8, 3);
			
			UserGroup group = entityManager.find(UserGroup.class, groupId);

			//entityManager.createQuery("delete from StorageServiceInfo ssi where ssi.enable = true and ssi.lockers.lockersId != " + lockers.getLockersId()).executeUpdate();

			entityManager.flush();
			
			Object[] objs = {lockers.getLocation().getDescription() + lockers.getLockersName(), storageServiceInfo.getStorageRfid()};
			
			ut.commit();
			
			String phone = storageServiceInfo.getPurchaser().getPhone();
			String email = storageServiceInfo.getPurchaser().getEmail();
			
			if (null != phone && !"".equals(phone) && informMap.containsKey(InformMessageLocal.SMS_INFORM)){
				String message = ((SmsInfo)informMap.get(InformMessageLocal.SMS_INFORM)).getSmsContent();
				
				message = MessageFormat.format(message, objs);
				
				logger.info("SMS message -> " + message);
				
				new SMSScheduler(phone, message, objs, "183", group.getSmsChannel(), group.getName(), false).start();
				
			} else if (null != email && !"".equals(email) && informMap.containsKey(InformMessageLocal.EMAIL_INFORM)){
				EmailInfo emailInfo = (EmailInfo) informMap.get(InformMessageLocal.EMAIL_INFORM);
				
				String message = emailInfo.getContent();
				
				message = MessageFormat.format(message, objs);
				
				logger.info("E-MAIL message -> " + message);
				
				new EMAILScheduler(email, emailInfo.getTitle(), message).start();
			}
			
			return storageServiceInfo.getStorageRfid();
		} catch (Exception e) {
			try {
				ut.rollback();
			} catch (Exception e1) {
				logger.error("Rollback fail\n" + e1.getMessage());
			}
			logger.error("Create storage service info fail!\n" + e.getMessage());
		} 

		return null;
	}
	
	@SuppressWarnings("unchecked")
	public JSONArray queryStorageServiceInfo(int userId, int groupId, String startTime, String endTime) {
		JSONArray result = new JSONArray();
		
		StringBuffer sql = new StringBuffer();
		sql.append("select ssi from StorageServiceInfo ssi where ssi.purchaser.purchaserId = ").append(userId);
		sql.append(" and ssi.groupId = ").append(groupId);
		
		if (null != startTime && !startTime.equals("")){
			sql.append(" and ssi.deliveryTime >= '").append(startTime).append("'");
		}
		
		if (null != endTime && !endTime.equals("")){
			sql.append(" and ssi.deliveryTime <= '").append(endTime).append("'");
		}
		
		sql.append(" order by ssi.deliveryTime desc");
		
		List<StorageServiceInfo> storageServiceInfos = entityManager.createQuery(sql.toString()).getResultList();
		
		for (StorageServiceInfo storageServiceInfo : storageServiceInfos) {
			JSONObject data = new JSONObject();
			data.accumulate("storage_code", storageServiceInfo.getStorageRfid());
			data.accumulate("store_order_code", storageServiceInfo.getNumber());
			data.accumulate("store_address", storageServiceInfo.getLockers().getLocation().getDescription() + storageServiceInfo.getLockers().getLockersName());
			data.accumulate("delivery_time", null == storageServiceInfo.getDeliveryTime() ? "" : DateTimeHelper.dateTimeToStr(storageServiceInfo.getDeliveryTime(), DateTimeHelper.DEFAULT_DATE_TIME_FORMAT));
			data.accumulate("takeout_time", null == storageServiceInfo.getTakeoutTime() ? "" : DateTimeHelper.dateTimeToStr(storageServiceInfo.getTakeoutTime(), DateTimeHelper.DEFAULT_DATE_TIME_FORMAT));
			data.accumulate("enable", storageServiceInfo.isEnable());
			data.accumulate("create_time", DateTimeHelper.dateTimeToStr(storageServiceInfo.getInsertTime(), DateTimeHelper.DEFAULT_DATE_TIME_FORMAT));
			
			result.add(data);
		}
		
		return result;
	}
	
	@SuppressWarnings("unchecked")
	public JSONArray queryStorageServiceKey(int userId, int groupId, String startTime, String endTime) {
		JSONArray result = new JSONArray();
		
		StringBuffer sql = new StringBuffer();
		sql.append("select lo.description, l.lockers_name, sgpn.arrival_time, sgpn.takeaway_time from order_information oi left join storage_grid_purchaser_news sgpn on oi.number = sgpn.order_information_number inner join storage_service_key ssk on oi.easy_storage_key = ssk.storage_service_key_id inner join lockers l on oi.lockers_id = l.lockers_id inner join location lo on l.location_id = lo.location_id where oi.order_type = 3 and ssk.purchaser_id = ").append(userId);
		sql.append(" and ssk.group_id = ").append(groupId);
		
		if (null != startTime && !startTime.equals("")){
			sql.append(" and sgpn.arrival_time >= '").append(startTime).append("'");
		}
		
		if (null != endTime && !endTime.equals("")){
			sql.append(" and sgpn.arrival_time <= '").append(endTime).append("'");
		}
		
		sql.append(" order by ssk.insert_time desc");
		
		List<Object[]> storageServiceKeys = entityManager.createNativeQuery(sql.toString()).getResultList();
		
		for (Object[] objs : storageServiceKeys) {
			JSONObject data = new JSONObject();
			
			data.accumulate("store_address", objs[0].toString() + objs[1].toString());
			data.accumulate("delivery_time", objs[2] == null ? "" : DateTimeHelper.dateTimeToStr(new Date(((Timestamp)objs[2]).getTime()), DateTimeHelper.DEFAULT_DATE_TIME_FORMAT));
			data.accumulate("takeout_time", objs[3] == null ? "" : DateTimeHelper.dateTimeToStr(new Date(((Timestamp)objs[3]).getTime()), DateTimeHelper.DEFAULT_DATE_TIME_FORMAT));
			result.add(data);
		}
		
		return result;
	}

	@SuppressWarnings("unchecked")
	private void autoCreateRfid(StorageServiceInfo storageServiceInfo, String lockersSn){
		String rfid = randomRfid();
		
		rfid += CommEntryUtil.transferCheckBit(CommEntryUtil.getFormatStr(CRC8.getCRC(rfid, Integer.parseInt(lockersSn)), 2));
		
		String passwd = CommEntryUtil.confuse(calculatePasswd(CommEntryUtil.bernstein(rfid)));
		
		List<Object> rfidList = entityManager.createQuery("select ssi.storageRfid from StorageServiceInfo ssi where ssi.storageRfid = '" + rfid + "'").getResultList();
		
		if (null != rfidList && rfidList.size() > 0)
			autoCreateRfid(storageServiceInfo, lockersSn);
		
		List<Object> passwdList = entityManager.createQuery("select ssi.storageRfid from StorageServiceInfo ssi where ssi.enable = true and ssi.storagePasswd = '" + passwd + "'").getResultList();
		
		if (null != passwdList && passwdList.size() > 0)
			autoCreateRfid(storageServiceInfo, lockersSn);
		
		storageServiceInfo.setStorageRfid(rfid);
		storageServiceInfo.setStoragePasswd(passwd);
	}

	private String randomRfid() {
		String rfid = String.valueOf((long) (Math.random() * 1000000));

		while (rfid.length() < 6) {
			rfid += String.valueOf((long) (Math.random() * 10));
		}

		return rfid;
	}
	
	private static String calculatePasswd(String rfid_sn) {
		StringBuffer sb = new StringBuffer();
		String done = rfid_sn.substring(7, 19);
		sb.append(done.charAt(3));
		sb.append(done.charAt(7));
		sb.append(done.charAt(4));
		sb.append(done.charAt(10));
		sb.append(done.charAt(2));
		sb.append(done.charAt(5));
		return sb.toString();
	}

}
